package com.module.ble.utils

import android.content.Context
import android.util.Base64
import android.util.Log
import androidx.work.CoroutineWorker
import androidx.work.WorkerParameters
import com.common.app.data.bean.CloudDownDataModel
import com.common.app.data.bean.UpKvDataModel
import com.common.app.helper.UserHelper
import com.common.app.utls.BrotliCompressionEx
import com.common.app.utls.report.ReportEventManager
import com.common.base.utils.JsonUtils
import com.module.ble.db.table.UserBloodOxygen
import com.module.ble.db.table.UserBodyTemperature
import com.module.ble.db.table.UserHeartRate
import com.module.ble.db.table.UserSleepInfo
import com.module.ble.db.table.UserSportRecord
import com.module.ble.db.table.UserStepsRelatedRecord
import com.module.ble.repo.UserStepsRelatedRecordRepo
import com.module.ble.utils.AizoSDKUtil.bloodOxygenMultiAdd2DB
import com.module.ble.utils.AizoSDKUtil.bodyTempMultiAdd2DB
import com.module.ble.utils.AizoSDKUtil.heartRateMultiAdd2DB
import com.module.ble.utils.AizoSDKUtil.sleepMultiAdd2DB
import com.module.ble.utils.AizoSDKUtil.sportsMultiAdd2DB
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.withContext

import kotlinx.coroutines.asCoroutineDispatcher
import kotlinx.coroutines.ensureActive
import kotlinx.coroutines.yield
import kotlinx.coroutines.CancellationException
import android.os.SystemClock
import com.module.ble.db.table.UserAcLevel
import com.module.ble.db.table.UserCalorie
import com.module.ble.db.table.UserHrv
import com.module.ble.db.table.UserRespiratoryRate
import com.module.ble.db.table.UserStand
import com.module.ble.db.table.UserStress
import com.module.ble.utils.AizoSDKUtil.acLevelMultiAdd2DB
import com.module.ble.utils.AizoSDKUtil.breathMultiAdd2DB
import com.module.ble.utils.AizoSDKUtil.calorieMultiAdd2DB
import com.module.ble.utils.AizoSDKUtil.hrvMultiAdd2DB
import com.module.ble.utils.AizoSDKUtil.standMultiAdd2DB
import com.module.ble.utils.AizoSDKUtil.stressMultiAdd2DB
import java.util.concurrent.Executors

/**
 *
 * 作者：sosou
 *
 * 版本：1.0
 *
 * 创建日期：5/8/2025
 *
 * 描述：
 * 云端数据解压缩Worker
 * 负责从CloudDownDataDao获取数据，进行Base64解码和Brotli解压缩
 * 处理完成后删除已处理的数据
 *
 * 修订历史：
 * - 修复并发问题：确保每批数据完全处理完成后再进行下一批
 *
 */
class CloudDataDecompressionV2Worker(context: Context, params: WorkerParameters) :
    CoroutineWorker(context, params) {

    companion object {
        private const val TAG = "CloudDataDecompressionV2Worker"
        private const val BATCH_SIZE = 100 // 每次处理100条数据
        // 使用专用单线程执行器，彻底与全局IO分离，避免与网络/DB抢占
        private val decompressionDispatcher = Executors.newSingleThreadExecutor { r ->
            Thread(r, "CloudData-Decompressor").apply {
                isDaemon = true
                priority = Thread.NORM_PRIORITY - 1
            }
        }.asCoroutineDispatcher()

        // 数据库操作使用共享IO
        private val dbDispatcher = Dispatchers.IO

        // 时间片：长批次处理时定期让出执行权，避免长时间占用导致系统卡顿
        private const val TIME_SLICE_MS = 4000L
    }

    override suspend fun doWork(): Result = withContext(decompressionDispatcher) {
        Log.d(TAG, "开始处理云端数据")
        try {
            var processedCount = 0
            var sliceStart = SystemClock.elapsedRealtime()

            while (true) {
                coroutineContext.ensureActive()

                // DB读取放到IO线程，避免阻塞解压专用线程
                val dataList = withContext(dbDispatcher) {
                    ReportEventManager.getCloudDownDataByIdDescSize(
                        UserHelper.getUserDbName(),
                        BATCH_SIZE
                    )
                }

                if (dataList.isEmpty()) {
                    Log.d(TAG, "没有更多数据需要处理，任务完成。总共处理了 $processedCount 条数据")
                    break
                }

                val successfullyProcessedData = mutableListOf<CloudDownDataModel>()

                for ((index, cloudData) in dataList.withIndex()) {
                    coroutineContext.ensureActive()
                    // 定期让出执行权，提升系统整体响应
                    if (index % 20 == 0) yield()

                    try {
                        if (!cloudData.data.isNullOrEmpty()) {
                            // Base64解码（CPU）
                            val decodedBytes = Base64.decode(cloudData.data, Base64.DEFAULT)
                            // Brotli解压缩（CPU）
                            val decompressedString = BrotliCompressionEx.decompressToStringByObd(decodedBytes)

                            // 业务处理（DB写入）放IO
                            processDecompressedData(cloudData.type, decompressedString)

                            successfullyProcessedData.add(cloudData)
                        } else {
                            // data为空也删除，避免死数据累积
                            successfullyProcessedData.add(cloudData)
                        }
                    } catch (e: Exception) {
                        Log.e(TAG, "处理数据 ID: ${cloudData.id} 时发生错误: ${e.message}", e)
                        // 失败的数据不加入删除列表
                    }
                }

                if (successfullyProcessedData.isNotEmpty()) {
                    // 删除已处理数据放到IO
                    withContext(dbDispatcher) {
                        ReportEventManager.delCloudDownData(successfullyProcessedData)
                    }
                    processedCount += successfullyProcessedData.size
                }

                // 本批数据小于BATCH_SIZE，说明已经处理完所有数据
                if (dataList.size < BATCH_SIZE) {
                    Log.d(TAG, "已处理完所有数据，任务完成。总共处理了 $processedCount 条数据")
                    break
                }

                // 时间片到了则让出，避免长时间霸占线程造成系统其他操作卡顿
                val elapsed = SystemClock.elapsedRealtime() - sliceStart
                if (elapsed >= TIME_SLICE_MS) {
                    Log.d(TAG, "达到时间片，暂时让出执行权。当前已处理 $processedCount 条")
                    yield()
                    sliceStart = SystemClock.elapsedRealtime()
                }
            }

            Result.success()
        } catch (ce: CancellationException) {
            // 明确传递取消，不吞掉，避免异常被误判为失败
            Log.w(TAG, "任务被取消：${ce.message}")
            throw ce
        } catch (e: Exception) {
            Log.e(TAG, "云端数据解压缩任务执行失败: ${e.message}", e)
            Result.failure()
        }
    }

    /**
     * 处理解压后的数据
     * 确保所有数据库操作完成后再返回
     */
    /**
     * 处理解压后的数据
     * 确保所有数据库操作完成后再返回
     */
    private suspend fun processDecompressedData(dataType: String?, decompressedString: String) {
        // 根据数据类型进行不同的处理
        val mData: List<UpKvDataModel> = JsonUtils.fromJsonList(decompressedString)

        when (dataType) {
            ServerHealthDataModelType.HEARTRATE.value -> withContext(dbDispatcher) {
                val hrData = arrayListOf<UserHeartRate>()
                mData.forEach {
                    JsonUtils.fromJson(it.value ?: "", UserHeartRate::class.java)?.let { beanIt ->
                        beanIt.sysStat = 1
                        hrData.add(beanIt)
                    }
                }
                heartRateMultiAdd2DB(hrData)
            }

            ServerHealthDataModelType.BLOODOXYGEN.value -> withContext(dbDispatcher) {
                val oxyData = arrayListOf<UserBloodOxygen>()
                mData.forEach {
                    JsonUtils.fromJson(it.value ?: "", UserBloodOxygen::class.java)?.let { beanIt ->
                        beanIt.sysStat = 1
                        oxyData.add(beanIt)
                    }
                }
                bloodOxygenMultiAdd2DB(oxyData)
            }

            ServerHealthDataModelType.BODYTEMP.value -> withContext(dbDispatcher) {
                val tmpData = arrayListOf<UserBodyTemperature>()
                mData.forEach {
                    JsonUtils.fromJson(it.value ?: "", UserBodyTemperature::class.java)
                        ?.let { beanIt ->
                            beanIt.sysStat = 1
                            tmpData.add(beanIt)
                        }
                }
                bodyTempMultiAdd2DB(tmpData)
            }

            ServerHealthDataModelType.STEPS.value -> withContext(dbDispatcher) {
                val stepsData = arrayListOf<UserStepsRelatedRecord>()
                mData.forEach {
                    JsonUtils.fromJson(it.value ?: "", UserStepsRelatedRecord::class.java)
                        ?.let { beanIt ->
                            beanIt.sysStat = 1
                            stepsData.add(beanIt)
                        }
                }
                UserStepsRelatedRecordRepo.instance.insertDistinct(stepsData)
            }

            ServerHealthDataModelType.EXERCISE.value -> withContext(dbDispatcher) {
                val sportData = arrayListOf<UserSportRecord>()
                mData.forEach {
                    JsonUtils.fromJson(it.value ?: "", UserSportRecord::class.java)?.let { beanIt ->
                        beanIt.sysStat = 1
                        sportData.add(beanIt)
                    }
                }
                sportsMultiAdd2DB(sportData)
            }

            ServerHealthDataModelType.SLEEP.value -> withContext(dbDispatcher) {
                val sleepData = arrayListOf<UserSleepInfo>()
                mData.forEach {
                    JsonUtils.fromJson(it.value ?: "", UserSleepInfo::class.java)?.let { beanIt ->
                        beanIt.sysStat = 1
                        sleepData.add(beanIt)
                    }
                }
                sleepMultiAdd2DB(sleepData)
            }
            ServerHealthDataModelType.HRV.value -> withContext(dbDispatcher) {
                val hrvData = arrayListOf<UserHrv>()
                mData.forEach {
                    JsonUtils.fromJson(it.value ?: "", UserHrv::class.java)?.let { beanIt ->
                        beanIt.sysStat = 1
                        hrvData.add(beanIt)
                    }
                }
                hrvMultiAdd2DB(hrvData)
            }
            ServerHealthDataModelType.CALORIE.value -> withContext(dbDispatcher) {
                val calorieData = arrayListOf<UserCalorie>()
                mData.forEach {
                    JsonUtils.fromJson(it.value ?: "", UserCalorie::class.java)?.let { beanIt ->
                        beanIt.sysStat = 1
                        calorieData.add(beanIt)
                    }
                }
                calorieMultiAdd2DB(calorieData)
            }
            ServerHealthDataModelType.STRESS.value -> withContext(dbDispatcher) {
                val stressData = arrayListOf<UserStress>()
                mData.forEach {
                    JsonUtils.fromJson(it.value ?: "", UserStress::class.java)?.let { beanIt ->
                        beanIt.sysStat = 1
                        stressData.add(beanIt)
                    }
                }
                stressMultiAdd2DB(stressData)
            }
            ServerHealthDataModelType.STAND.value -> withContext(dbDispatcher) {
                val standData = arrayListOf<UserStand>()
                mData.forEach {
                    JsonUtils.fromJson(it.value ?: "", UserStand::class.java)?.let { beanIt ->
                        beanIt.sysStat = 1
                        standData.add(beanIt)
                    }
                }
                standMultiAdd2DB(standData)
            }
            ServerHealthDataModelType.BREATH.value -> withContext(dbDispatcher) {
                val breathData = arrayListOf<UserRespiratoryRate>()
                mData.forEach {
                    JsonUtils.fromJson(it.value ?: "", UserRespiratoryRate::class.java)?.let { beanIt ->
                        beanIt.sysStat = 1
                        breathData.add(beanIt)
                    }
                }
                breathMultiAdd2DB(breathData)
            }
            ServerHealthDataModelType.ACLEVEL.value -> withContext(dbDispatcher) {
                val acLevelList = arrayListOf<UserAcLevel>()
                mData.forEach {
                    JsonUtils.fromJson(it.value ?: "", UserAcLevel::class.java)?.let { beanIt ->
                        beanIt.sysStat = 1
                        acLevelList.add(beanIt)
                    }
                }
                acLevelMultiAdd2DB(acLevelList)
            }

            else -> {
                // 未知类型忽略
            }
        }
    }
}